package com.example.demo.core.resolver;

import com.example.demo.core.annotations.ApiNotNull;
import com.example.demo.core.exception.ProgramException;
import com.example.demo.core.util.JsonUtil;
import com.example.demo.core.util.RegexUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import java.lang.reflect.Method;
import java.util.Optional;

/**
 * @author yj
 * @date 2021-07-24 21:51
 */
@Slf4j
public class ApiNotNullResolver implements HandlerMethodArgumentResolver {

    /**
     * 判断方法内参数是否存在
     *
     * @param methodParameter 方法
     * @return true 存在且不为空  | false 不存在或者为空
     */
    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        return methodParameter.hasParameterAnnotations() && methodParameter.hasParameterAnnotation(ApiNotNull.class);
    }

    @Override
    public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
        //获取参数注解
        ApiNotNull apiNotNull = Optional
                .ofNullable(methodParameter.getParameterAnnotation(ApiNotNull.class))
                .orElseThrow(() -> new ProgramException("缺少必要参数"));
        //获取注解标明参数value
        String parameter = nativeWebRequest.getParameter(methodParameter.getParameter().getName());
        //获取注解标明参数的类型
        Class<?> parameterType = methodParameter.getParameterType();
        //1.第一步注解是否管控参数是否能为null
        //2.第二步根据注解message提示
        try {
            //转换类型
            Object value = RegexUtil.checkStringIsNull(parameter) ? null : JsonUtil.jsonObjectToType(parameter, parameterType);
            //不能为null
            if (!apiNotNull.existValueNull()) {
                if (RegexUtil.checkObjectIsNull(value)) {
                    //获取方法名(避免在判断前获取太多东西，在最后主动抛异常时再获取)
                    Method method = Optional
                            .ofNullable(methodParameter.getMethod())
                            .orElseThrow(() -> new ProgramException("方法为null"));
                    log.info("方法:{}上的参数:{}不能为null", method.getName(), methodParameter.getParameter().getName());
                    throw new ProgramException(
                            RegexUtil.checkStringIsNull(apiNotNull.message()) ?
                                    "方法:" + method.getName() + "上的参数:" + methodParameter.getParameter().getName() + "不能为null" :
                                    apiNotNull.message()
                    );
                }
            }
            return value;
        } catch (Exception e) {
            if (e instanceof ProgramException) {
                throw e;
            }
            throw new ProgramException("系统异常" + e.getMessage());
        }
    }
}
